package com.seven.good.controller;

import com.seven.good.exception.AuctionException;
import com.seven.good.pojo.BidRecord;
import com.seven.good.pojo.Good;
import com.seven.good.server.WebSocketServer;
import com.seven.good.service.AuctionService;
import com.seven.good.service.GoodService;
import com.seven.good.service.OrdersService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.ModelAndView;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Controller
public class AuctionController {

    @Autowired
    GoodService goodService;

    @Autowired
    AuctionService auctionService;

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    WebSocketServer webSocketServer;

    @Autowired
    OrdersService ordersService;

    /**
     * @Description：获取当前商品的竞价室
     * @Author: ytj
     * @param: gid 商品编号
     * @return ModelAndView 视图模型
     * @CreateDate:  19/10/24
     */
    //@LogAnno(logType = LogTypeEnum.OPERATE_LOG,msg = "竞价室")
    @GetMapping("/bidroom/{gid}")
    public ModelAndView toBidPage(@PathVariable Integer gid){

        ModelAndView mv = new ModelAndView("bidroom");
        try {
            // 获取竞价商品，从redis中获取
            Good good = (Good)redisTemplate.opsForValue().get(gid.toString());

            // redis中没有该商品
            if(good==null){
                throw new AuctionException("当前竞拍品时间结束，无法进入该商品竞价室");
            }

            // 获取redis该商品最新的竞价记录（1条）
            BidRecord bidRecord = (BidRecord) redisTemplate.opsForValue().get("bidroom::"+gid);

            // 没有竞价记录，初始化一条空记录
            if(bidRecord==null){
                bidRecord = new BidRecord();
            }

            // 存入模型视图中
            mv.addObject("bidgood",good);
            mv.addObject("bidRecord",bidRecord);

        } catch (Exception e) {

            // 错误页
            mv.setViewName("auctionerror");
            mv.addObject("msg",e.getMessage());
        }
        return mv;
    }

    /**
     * @Description：获取商品的竞价记录表
     * @Author: ytj
     * @param: gid 商品编号
     * @return Map 集合
     * @exception:  AuctionException
     * @CreateDate:  19/10/24
     */
    @RequestMapping("/bidlist/{gid}")
    @ResponseBody
    //@CrossOrigin
    public Map bidRecordList(@PathVariable Integer gid){

        Map map = new HashMap();
        try {
            List<BidRecord> bidlist = auctionService.listRecordListById(gid);

            if(bidlist.size()>0){
                map.put("bidlist",bidlist);
                map.put("code",200);
            }else{
                // 没有竞拍记录
                map.put("code",300);
            }
        } catch (AuctionException e) {
            map.put("msg",e.getMessage());
            map.put("code",500);
        }
        return map;
    }

    /**
     * @Description：竞价
     * @Author: ytj
     * @param: bidRecord
     * @return Map 集合
     * @exception: AuctionException
     * @CreateDate:  19/10/24
     */
    //@LogAnno(logType = LogTypeEnum.OPERATE_LOG,msg = "竞价")
    @PostMapping("/bid")
    @ResponseBody
    public Map bidInRoom(BidRecord bidRecord){

        // 获取当前用户ID
        Object id = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
                .getRequest().getSession().getAttribute("userId");
        bidRecord.setUid((Integer) id);

        Map map = new HashMap();
        try {
            // 非空验证
            if(bidRecord==null){
                map.put("code",500);
                map.put("msg","为获取到竞价记录");
            }else{
                // 验证
                if(verify(bidRecord)){

                    // 向数据库插入记录
                    auctionService.doRecordInBidroom(bidRecord);

                    // 更新数据库当前价格和竞拍次数（+1）
                    goodService.updateNowPriceAndBidNo(bidRecord);

                    map.put("code",200);
                    map.put("msg","竞价成功");
                }else{
                    // 执行不能
                    map.put("code",500);
                    map.put("msg","竞价室未知验证错误");
                }
            }
        } catch (AuctionException e) {
            map.put("code",500);
            map.put("msg",e.getMessage());
        }
        return map;
    }

    /**
     * @Description：获取竞价剩余的持续时间
     * @Author: ytj
     * @param: gid 商品ID
     * @return Long 持续时间（秒）
     * @CreateDate:  19/10/24
     */
    //@LogAnno(logType = LogTypeEnum.OPERATE_LOG,msg = "延时")
    @ResponseBody
    @GetMapping("/getDuration")
    public Long getDuration(Integer gid){
        Good good = (Good) redisTemplate.opsForValue().get(gid.toString());
        if(good==null){
            return 0L;
        }
        // 返回剩余的持续时间
        return good.getDurationSeconds();
    }

    /**
     * @Description：取消当前竞拍品
     * @Author: ytj
     * @param: gid 商品编号
     * @return Map 消息集合
     * @CreateDate:  19/10/29
     */
    @ResponseBody
    @GetMapping("/cancleBid")
    public Map cancelBid(Integer gid){
        Map map = new HashMap();
        try {
            if(auctionService.cancleBid(gid)){
                map.put("msg","成功取消了竞拍品");
            }else {
                map.put("msg","你不能取消已经开始竞拍的商品或当前竞拍品并不存在");
            }
            map.put("code",200);
        } catch (AuctionException e) {
            map.put("code",500);
            map.put("msg",e.getMessage());
        }
        return map;
    }

    // 竞拍验证方法
    public boolean verify(BidRecord bidRecord){
        String gid = bidRecord.getGid().toString();
        try {
            // 验证时间，以redis的key死亡为准
            if(!redisTemplate.hasKey(gid)){
                throw new AuctionException("竞拍时间已结束");
            }

            // 在redis中，获取当前id的竞拍商品
            Good good = (Good)redisTemplate.opsForValue().get(gid);

            //验证是否为本人
            Integer trueid = good.getPublisher();
            if(trueid==null || trueid==bidRecord.getUid()){
                throw new AuctionException("发布人不能参加或发布人不存在");
            }

            //验证是否交了保证金
            if(ordersService.isHaveDepository(trueid,bidRecord.getGid())!=1){
                throw new AuctionException("未交付保证金，请先交保证金");
            }

            // 取出redis的最新该条商品的出价记录
            BidRecord oldbidRecord = (BidRecord) redisTemplate.opsForValue().get("bidroom::"+gid);

            // 验证价格
            if(oldbidRecord!=null){
                if(bidRecord.getBidPrice()-oldbidRecord.getBidPrice()<good.getRangePrice()){
                    throw new AuctionException("价格低于加价幅度");
                }else{
                    // 没人出价，数据库的原始价格验证（前端已有初步验证）,转换为BigDecimal对象
                    if(new BigDecimal(bidRecord.getBidPrice()).compareTo(
                            good.getStartPrice().add(new BigDecimal(good.getRangePrice()))
                    )<0){
                        throw new AuctionException("价格低于加价幅度");
                    }
                }
            }

            // 验证剩余过期时间
            if(redisTemplate.getExpire(gid)-300L<0){
                // 延长时间
                redisTemplate.expire(gid,redisTemplate.getExpire(gid)+300L, TimeUnit.SECONDS);

                // 更新数据库结束时间
                goodService.updateEndtime(bidRecord.getGid());

                // 重数据库重新取出该商品，并更新redis，更新增加后的过期时间
                Good newgood = goodService.getGoodById(bidRecord.getGid());
                Long time = (newgood.getEndTime().getTime()-new Date().getTime())/1000;
                redisTemplate.opsForValue().set(gid,newgood,time,TimeUnit.SECONDS);

                // 通知WebSocket推送延迟时间的消息。代码300
                webSocketServer.onMessage("300");
            }
        } catch (AuctionException e){
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            throw new AuctionException("验证异常");
        }
        return true;
    }

    /*ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
    HttpServletRequest request = requestAttributes.getRequest();
    HttpServletResponse response = requestAttributes.getResponse();
    //从session里面获取对应的值
    String myValue = (String) requestAttributes.getAttribute("my_value", RequestAttributes.SCOPE_SESSION);*/
}
